﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace Tcvt.Packages
{
    public partial class PendingChangesForm : Form
    {
        #region Constants
        private const string ITEM_COUNT_TEMPLATE = "Number of items checked/total: {0}/{1}";
        #endregion

        #region Private Fields
        private PendingChange[] _checkedPendingChanges = new PendingChange[0];
        private PendingChange[] _pendingChanges;
        private CheckinNoteFieldDefinition[] _checkinNoteFieldDefinitions;
        private CheckinNote _checkinNote = null;
        private string _checkinComment = "";
        private string _policyOverrideComment = "";
        private bool _overridePolicyViolations;
        private TeamFoundationServer _tfs;
        #endregion

        #region Constructor
        public PendingChangesForm()
        {
            InitializeComponent();
        }
        #endregion

        #region Public Properties
        public PendingChange[] PendingChanges
        {
            get
            {
                return _pendingChanges;
            }
            set
            {
                _pendingChanges = value;
            }
        }

        public PendingChange[] CheckedPendingChanges
        {
            get
            {
                return _checkedPendingChanges;
            }
            set
            {
                _checkedPendingChanges = value;
            }
        }

        public CheckinNoteFieldDefinition[] CheckinNoteFieldDefinitions
        {
            get
            {
                return _checkinNoteFieldDefinitions;
            }
            set
            {
                _checkinNoteFieldDefinitions = value;
            }
        }

        public CheckinNote CheckinNote
        {
            get
            {
                return _checkinNote;
            }
            set
            {
                _checkinNote = value;
            }
        }

        public string CheckinComment
        {
            get
            {
                return _checkinComment;
            }
            set
            {
                _checkinComment = value;
            }
        }

        public string PolicyOverrideComment
        {
            get
            {
                return _policyOverrideComment;
            }
            set
            {
                _policyOverrideComment = value;
            }
        }

        public bool OverridePolicyViolations
        {
            get
            {
                return _overridePolicyViolations;
            }
            set
            {
                _overridePolicyViolations = value;
            }
        }

        public TeamFoundationServer Tfs
        {
            get
            {
                return _tfs;
            }
            set
            {
                _tfs = value;
            }
        }

        public WorkItemCheckinInfo[] SelectedWorkItems
        {
            get
            {
                if (this.SelectedWorkItemsDataGridView.Rows.Count > 0)
                {
                    // Get the work items.
                    List<WorkItemCheckinInfo> workItemCheckinInfoList = new List<WorkItemCheckinInfo>();
                    for (int i = 0; i < this.SelectedWorkItemsDataGridView.Rows.Count; i++)
                    {
                            WorkItem workItem = (WorkItem)this.SelectedWorkItemsDataGridView.Rows[i].Tag;
                            WorkItemCheckinInfo item = new WorkItemCheckinInfo(workItem, WorkItemCheckinAction.Associate);
                            workItemCheckinInfoList.Add(item);
                    }

                    return workItemCheckinInfoList.ToArray();
                }
                else
                    return null;
            }
        }
        #endregion

        #region Event Handlers
        private void ShelveSelectedChangesButton_Click(object sender, EventArgs e)
        {
            if (PendingChangesCheckedListBox.CheckedItems.Count > 0)
            {
                _checkedPendingChanges = new PendingChange[PendingChangesCheckedListBox.CheckedItems.Count];
                for (int i = 0; i < PendingChangesCheckedListBox.CheckedItems.Count; i++)
                {
                    string item = (string)PendingChangesCheckedListBox.CheckedItems[i];
                    int startIndex = item.LastIndexOf('\t');
                    int pendingChangeIndex = Convert.ToInt32(item.Substring(startIndex + 1, item.Length - startIndex - 1)) - 1;
                    _checkedPendingChanges[i] = _pendingChanges[pendingChangeIndex];
                }

                // Set the checkin notes.
                IList<CheckinNoteFieldValue> checkinNotesList = new List<CheckinNoteFieldValue>();
                string labelNamePrefix = "CheckNoteNameLabel";
                string textboxNamePrefix = "CheckNoteValueTextBox";
                bool hasChanges = false;
                foreach (Control control in this.CheckinNotesTabPage.Controls)
                {
                    if (control is Label && control.Name.StartsWith(labelNamePrefix))
                    {
                        string index = control.Name.Substring(labelNamePrefix.Length);
                        string fieldValue = CheckinNotesTabPage.Controls[string.Format("{0}{1}", textboxNamePrefix, index)].Text;

                        checkinNotesList.Add(
                            new CheckinNoteFieldValue(
                                control.Text,
                                fieldValue));

                        if (fieldValue.Length > 0 && !hasChanges)
                            hasChanges = true;
                    }
                }

                if (hasChanges)
                {
                    CheckinNoteFieldValue[] checkinNoteFields = checkinNotesList.ToArray();
                    _checkinNote = new CheckinNote(checkinNoteFields);
                }

                this.CheckinComment = this.CommentsTextBox.Text;
                this.OverridePolicyViolations = this.OverridePolicyViolationsCheckBox.Checked;
                this.PolicyOverrideComment = this.OverridePolicyViolations ? this.PolicyOverrideCommentTextBox.Text : string.Empty;
                this.Close();
            }
            else
            {
                Utils.ShowErrorMessageBox("At least one items should be checked.");
            }
        }

        private void CancelPendingChangesButton_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void PendingChangesForm_Load(object sender, EventArgs e)
        {
            // Remove the last tab until it is implemented.
            this.PendingChangesTabControl.TabPages.RemoveAt(3);
            this.CommentsTextBox.Text = this.CheckinComment;
            this.OverridePolicyViolationsCheckBox.Checked = this.OverridePolicyViolations;
            this.PolicyOverrideCommentTextBox.Text = this.PolicyOverrideComment;
            this.PolicyViolationsOverrideCommentLabel.Enabled = false;
            this.PolicyOverrideCommentTextBox.Enabled = false;

            for (int i = 0; i < _pendingChanges.Length; i++)
            {
                PendingChangesCheckedListBox.Items.Add(string.Format("{0}\t[{1}]\t{2}",
                                                       _pendingChanges[i].LocalOrServerItem,
                                                       _pendingChanges[i].ChangeTypeName,
                                                       (i + 1)
                                                       ),
                                                       true);
            }

            // Populate the checkin notes:
            PopulateCheckinNotesTab();

            int itemCount = PendingChangesCheckedListBox.Items.Count;
            this.ItemCountLabel.Text = string.Format(ITEM_COUNT_TEMPLATE,
                itemCount,
                itemCount);

            this.CommentsTextBox.Focus();
            this.CommentsTextBox.SelectAll();
        }

        private void CheckAllItemsButton_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < PendingChangesCheckedListBox.Items.Count; i++)
            {
                PendingChangesCheckedListBox.SetItemChecked(i, true);
            }
        }

        private void UncheckAllItemsButton_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < PendingChangesCheckedListBox.Items.Count; i++)
            {
                PendingChangesCheckedListBox.SetItemChecked(i, false);
            }
        }

        private void PendingChangesCheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            this.ItemCountLabel.Text = string.Format(ITEM_COUNT_TEMPLATE,
                PendingChangesCheckedListBox.CheckedItems.Count + (e.NewValue == CheckState.Checked ? 1 : -1),
                PendingChangesCheckedListBox.Items.Count);

            this.ShelveSelectedChangesButton.Enabled =
                (PendingChangesCheckedListBox.CheckedItems.Count > 1 && e.NewValue == CheckState.Unchecked)
                || e.NewValue == CheckState.Checked;
        }

        private void OverridePolicyViolationsCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (this.OverridePolicyViolationsCheckBox.Checked)
            {
                this.PolicyViolationsOverrideCommentLabel.Enabled = true;
                this.PolicyOverrideCommentTextBox.Enabled = true;
            }
            else
            {
                this.PolicyViolationsOverrideCommentLabel.Enabled = false;
                this.PolicyOverrideCommentTextBox.Enabled = false;
            }
        }

        private void CheckinNotesTabPage_Leave(object sender, System.EventArgs e)
        {
            string textboxNamePrefix = "CheckNoteValueTextBox";

            foreach (Control control in this.CheckinNotesTabPage.Controls)
            {
                if (control is TextBox && control.Name.StartsWith(textboxNamePrefix))
                {
                    string fieldValue = control.Text;

                    if (fieldValue.Length == 0 && (string)control.Tag == "*")
                    {
                        this.CheckinNotesTabPage.ImageIndex = 0;
                        return;
                    }
                }
            }

            this.CheckinNotesTabPage.ImageIndex = -1;
        }

        private void RemoveWorkItemButton_Click(object sender, EventArgs e)
        {
            int numSelected = this.SelectedWorkItemsDataGridView.SelectedRows.Count;
            if (numSelected <= 0)
            {
                Utils.ShowWarningMessageBox("The are no work items selected.");
                return;
            }

            //DialogResult result = MessageBox.Show("Are you sure you want to remove the selected work items(s)?", Utils.MessageBoxTitle,
            //    MessageBoxButtons.YesNo,
            //    MessageBoxIcon.Question,
            //    MessageBoxDefaultButton.Button2);

            // Remove the selected rows from the data grid view directly.
            //if (result == DialogResult.Yes)
            //{
            foreach (DataGridViewRow row in this.SelectedWorkItemsDataGridView.SelectedRows)
            {
                this.SelectedWorkItemsDataGridView.Rows.Remove(row);
            }
            //}

            if (this.SelectedWorkItemsDataGridView.Rows.Count <= 0)
            {
                this.RemoveWorkItemButton.Enabled = false;
            }

            UpdateTabTitle();
        }

        private void AddWorkItemButton_Click(object sender, EventArgs e)
        {
            string workItemId = this.WorkItemIdTextBox.Text.Trim();
            if (string.IsNullOrEmpty(workItemId) || workItemId.Trim().Length <= 0)
            {
                Utils.ShowWarningMessageBox("Please enter a work item id.");
                this.WorkItemIdTextBox.Select();
                return;
            }

            int numericId = 0;
            try
            {
                numericId = Convert.ToInt32(workItemId.Trim());
            }
            catch (Exception ex)
            {
                Utils.LogMessage("AddWorkItemButton_Click: ErrorMessage:" + ex.Message);
                Utils.LogMessage("AddWorkItemButton_Click: StackTrace:" + ex.StackTrace);

                Utils.ShowWarningMessageBox("Work item id must be an integer.");
                this.WorkItemIdTextBox.Select();
                return;
            }

            // Check if the work item is alreadty in the grid:
            bool found = false;

            if (this.SelectedWorkItemsDataGridView.Rows.Count > 0)
            {
                found = (from DataGridViewRow existingRow in this.SelectedWorkItemsDataGridView.Rows
                         where (int)existingRow.Cells[0].Value == numericId
                         select existingRow).Count() > 0;
            }

            if (found)
            {
                Utils.ShowWarningMessageBox(
                    string.Format("Work item with id {0} has already been added to the list.", numericId));
                this.WorkItemIdTextBox.Select();
                return;
            }

            WorkItemStore store = (WorkItemStore)_tfs.GetService(typeof(WorkItemStore));
            if (store.Projects.Count <= 0)
            {
                Utils.LogMessage("There are no projects on this server's Work Item Store.", LogType.Error);
                Utils.ShowErrorMessageBox("There are no projects on this server's Work Item Store.\r\n" +
                    "Cannot find specified work item.");
                return;
            }

            WorkItem workItem = null;

            try
            {
                workItem = store.GetWorkItem(numericId);

                if (workItem == null)
                {
                    Utils.LogMessage(string.Format(
                        "There are no work items with the specified id ({0}).",
                        numericId), LogType.Error);
                    Utils.ShowErrorMessageBox(string.Format(
                        "There are no work items with the specified id ({0}).",
                        numericId));
                    return;
                }
            }
            catch (Exception ex)
            {
                Utils.LogMessage("AddWorkItemButton_Click: ErrorMessage:" + ex.Message);
                Utils.LogMessage("AddWorkItemButton_Click: StackTrace:" + ex.StackTrace);

                Utils.ShowWarningMessageBox("Invalid work item id or id cannot be found. Please specify a different id.");
                this.WorkItemIdTextBox.Select();
                return;
            }

            DataGridViewRow row = null;
            DataGridViewTextBoxCell cell = null;

            row = new DataGridViewRow();

            cell = new DataGridViewTextBoxCell();
            cell.Value = numericId;
            row.Cells.Add(cell);

            cell = new DataGridViewTextBoxCell();
            cell.Value = workItem.Title;
            row.Cells.Add(cell);

            row.Tag = workItem;

            this.SelectedWorkItemsDataGridView.Rows.Add(row);

            this.RemoveWorkItemButton.Enabled = true;
            this.WorkItemIdTextBox.Clear();

            UpdateTabTitle();
        }
        #endregion

        #region Private Methods
        private void UpdateTabTitle()
        {
            int numRows = this.SelectedWorkItemsDataGridView.Rows.Count;
            this.WorkItemsTabPage.Text = string.Format("Work Items ({0})", numRows);
        }

        private void PopulateCheckinNotesTab()
        {
            if (_checkinNoteFieldDefinitions != null && _checkinNoteFieldDefinitions.Count() > 0)
            {
                int top = 30;
                int counter = 0;
                bool hasRequiredFields = false;

                foreach (var checkinFieldDefinition in _checkinNoteFieldDefinitions.OrderBy(item => item.DisplayOrder))
                {
                    Label checkNoteNameLabel = new Label();
                    checkNoteNameLabel.Name = string.Format("CheckNoteNameLabel{0}", counter);
                    checkNoteNameLabel.Top = top + 10;
                    checkNoteNameLabel.Left = 10;
                    checkNoteNameLabel.Height = 16;
                    checkNoteNameLabel.Width = 200;
                    checkNoteNameLabel.TextAlign = ContentAlignment.BottomLeft;
                    checkNoteNameLabel.BackColor = Color.Transparent;
                    checkNoteNameLabel.Text = checkinFieldDefinition.Name;
                    if (checkinFieldDefinition.Required)
                        checkNoteNameLabel.Font = new Font(checkNoteNameLabel.Font, FontStyle.Bold);
                    checkNoteNameLabel.Visible = true;

                    TextBox checkNoteValueTextBox = new TextBox();
                    checkNoteValueTextBox.Name = string.Format("CheckNoteValueTextBox{0}", counter);
                    checkNoteValueTextBox.Top = top + 10;
                    checkNoteValueTextBox.Left = 220;
                    checkNoteValueTextBox.Height = 16;
                    checkNoteValueTextBox.Width = 350;
                    checkNoteValueTextBox.TextAlign = HorizontalAlignment.Left;
                    checkNoteValueTextBox.Visible = true;
                    if (checkinFieldDefinition.Required)
                        checkNoteValueTextBox.Tag = "*";

                    this.CheckinNotesTabPage.Controls.Add(checkNoteNameLabel);
                    this.CheckinNotesTabPage.Controls.Add(checkNoteValueTextBox);

                    if (checkinFieldDefinition.Required && !hasRequiredFields)
                        hasRequiredFields = true;

                    top += checkNoteNameLabel.Height + 10;
                    counter++;
                }

                // Set an icon on the tab to indicate there are some required fields.
                if (hasRequiredFields)
                {
                    this.CheckinNotesTabPage.ImageIndex = 0;
                }
            }
        }
        #endregion
    }
}
